//
//  ViewController.m
//  DemoPhotoViewer
//
//  Created by 唐可雄 on 17/2/12.
//  Copyright © 2017年 swustyc. All rights reserved.
//

#import "ViewController.h"

@import MapKit;
@import ImageIO;

#import "YCPhotoAnnotation.h"

@interface ViewController ()<MKMapViewDelegate>

@property (strong, nonatomic) MKMapView *cacheMapView;
@property (weak, nonatomic) IBOutlet MKMapView *mapView;

@end

@implementation ViewController

#pragma mark - UIViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.cacheMapView = [[MKMapView alloc] init];
    
    [self configMapView];
    
    [self loadPhotoes];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - View Config

- (void)configMapView {
    MKCoordinateRegion newRegion;
    newRegion.center = CLLocationCoordinate2DMake(38.002493, -119.9078987);
    newRegion.span.latitudeDelta = 5.0;
    newRegion.span.longitudeDelta = 5.0;
    self.mapView.region = newRegion;
}

#pragma mark - Model

- (NSArray *)photoSetFromPath:(NSString *)path {
    NSMutableArray *photoes = [[NSMutableArray alloc] init];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue setMaxConcurrentOperationCount:8];
    
    NSArray *photoPaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:path];
    for (NSString *photoPath in photoPaths) {
        [queue addOperationWithBlock:^{
            NSData *imageData = [NSData dataWithContentsOfFile:photoPath];
            CGDataProviderRef dataProviderRef = CGDataProviderCreateWithCFData((CFDataRef)imageData);
            CGImageSourceRef imageSourceRef = CGImageSourceCreateWithDataProvider(dataProviderRef, NULL);
            NSDictionary *imageProperties = (NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL));
            // 查看图片是否有地理标记
            NSDictionary *gpsInfo = imageProperties[(NSString *)kCGImagePropertyGPSDictionary];
            if (gpsInfo) {
                CLLocationCoordinate2D coord;
                coord.latitude = [gpsInfo[(NSString *)kCGImagePropertyGPSLatitude] doubleValue];
                coord.longitude = [gpsInfo[(NSString *)kCGImagePropertyGPSLongitude] doubleValue];
                if ([gpsInfo[(NSString *)kCGImagePropertyGPSLatitudeRef] isEqualToString:@"S"])
                    coord.latitude = coord.latitude * -1;
                if ([gpsInfo[(NSString *)kCGImagePropertyGPSLongitudeRef] isEqualToString:@"W"])
                    coord.longitude = coord.longitude * -1;
                
                NSString *fileName = [[photoPath lastPathComponent] stringByDeletingPathExtension];
                YCPhotoAnnotation *photo = [[YCPhotoAnnotation alloc] initWithImagePath:photoPath title:fileName coordinate:coord];
                
                @synchronized(photoes) {
                    [photoes addObject:photo];
                }
            }
            
            if (imageSourceRef)
                CFRelease(imageSourceRef);
            
            if (imageProperties)
                CFRelease(CFBridgingRetain(imageProperties));
            
            if (dataProviderRef)
                CFRelease(dataProviderRef);
        }];
    }
    
    [queue waitUntilAllOperationsAreFinished];
    
    return photoes;
}

- (id<MKAnnotation>)annotationInGrid:(MKMapRect)gridMapRect usingAnnotations:(NSSet *)annotations {
    // 如果已经有显示，那么就不用再选择
    NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
    NSSet *annotationsForGridSet = [annotations objectsPassingTest:^BOOL(id obj, BOOL *stop) {
        BOOL returnValue = ([visibleAnnotationsInBucket containsObject:obj]);
        if (returnValue)
        {
            *stop = YES;
        }
        return returnValue;
    }];
    
    if (annotationsForGridSet.count != 0) {
        return [annotationsForGridSet anyObject];
    }
    
    // 否则，按照大家到格子中心的距离，来选择一个最近的
    MKMapPoint centerMapPoint = MKMapPointMake(MKMapRectGetMidX(gridMapRect), MKMapRectGetMidY(gridMapRect));
    NSArray *sortedAnnotations = [[annotations allObjects] sortedArrayUsingComparator:^(id obj1, id obj2) {
        MKMapPoint mapPoint1 = MKMapPointForCoordinate(((id<MKAnnotation>)obj1).coordinate);
        MKMapPoint mapPoint2 = MKMapPointForCoordinate(((id<MKAnnotation>)obj2).coordinate);
        
        CLLocationDistance distance1 = MKMetersBetweenMapPoints(mapPoint1, centerMapPoint);
        CLLocationDistance distance2 = MKMetersBetweenMapPoints(mapPoint2, centerMapPoint);
        
        if (distance1 < distance2) {
            return NSOrderedAscending;
        } else if (distance1 > distance2) {
            return NSOrderedDescending;
        }
        
        return NSOrderedSame;
    }];
    
    return [sortedAnnotations firstObject];
}

- (void)updateVisibleAnnotations {
    // 此值用于控制屏幕外的标注的数量This value to controls the number of off screen annotations are displayed.
    // 值越大，性能越差
    // 值越小，性能越好
    static float marginFactor = 2.0;
    // 地图方块对应的像素逻辑点单位
    static float bucketSize = 60.0;

    // 获取self.mapView所展示的可见区域，单位：米
    MKMapRect visibleMapRect = [self.mapView visibleMapRect];
    // MKMapRectInset(rect, x, y)，最终的宽度为rect.width+2*x, 高度为rect.height+2*y
    MKMapRect adjustedVisibleMapRect = MKMapRectInset(visibleMapRect, -marginFactor * visibleMapRect.size.width, -marginFactor * visibleMapRect.size.height);
    
    // 获取self.view的原点所对应的经纬度
    CLLocationCoordinate2D leftCoordinate = [self.mapView convertPoint:CGPointZero toCoordinateFromView:self.view];
    // 获取self.view中的CGPointMake(bucketSize, 0)所对应的经纬度
    CLLocationCoordinate2D rightCoordinate = [self.mapView convertPoint:CGPointMake(bucketSize, 0) toCoordinateFromView:self.view];
    // 一格代表的经纬度跨度
    double gridSize = MKMapPointForCoordinate(rightCoordinate).x - MKMapPointForCoordinate(leftCoordinate).x;
    // 一格
    MKMapRect gridMapRect = MKMapRectMake(0, 0, gridSize, gridSize);
    
    // 将调整好的地图，变成整数个数的格子
    double startX = floor(MKMapRectGetMinX(adjustedVisibleMapRect) / gridSize) * gridSize;
    double startY = floor(MKMapRectGetMinY(adjustedVisibleMapRect) / gridSize) * gridSize;
    double endX = floor(MKMapRectGetMaxX(adjustedVisibleMapRect) / gridSize) * gridSize;
    double endY = floor(MKMapRectGetMaxY(adjustedVisibleMapRect) / gridSize) * gridSize;
    
    // 选一块来展示
    gridMapRect.origin.y = startY;
    while (MKMapRectGetMinY(gridMapRect) <= endY) {
        gridMapRect.origin.x = startX;
        
        while (MKMapRectGetMinX(gridMapRect) <= endX) {
            NSSet *visibleAnnotationsInBucket = [self.cacheMapView annotationsInMapRect:gridMapRect];
            
            if (visibleAnnotationsInBucket.count > 0) {
                // 选一个标注出来作为代表，然后全部，包括自己作为子标注
                YCPhotoAnnotation *annotationForGrid = (YCPhotoAnnotation *)[self annotationInGrid:gridMapRect usingAnnotations:visibleAnnotationsInBucket];
                annotationForGrid.containedAnnotations = [visibleAnnotationsInBucket allObjects];
                
                NSLog(@"%@", annotationForGrid);
                [self.mapView addAnnotation:annotationForGrid];
                
                for (YCPhotoAnnotation *annotation in visibleAnnotationsInBucket) {
                    // 设置子标注的父标注
                    annotation.clusterAnnotation = annotationForGrid;
                    if (annotation != annotationForGrid) {
                        annotation.containedAnnotations = nil;
                    }
                }
            }
            
            gridMapRect.origin.x += gridSize;
        }
        
        gridMapRect.origin.y += gridSize;
    }
}

- (void)loadPhotoes {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSArray *photoes = [self photoSetFromPath:@"PhotoSet"];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.cacheMapView addAnnotations:photoes];
            
            [self updateVisibleAnnotations];
        });
    });
}

#pragma mark - MKMapViewDelegate

- (void)mapView:(MKMapView *)aMapView regionDidChangeAnimated:(BOOL)animated {
    [self.mapView deselectAnnotation:[self.mapView.selectedAnnotations firstObject] animated:NO];
    [self updateVisibleAnnotations];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    
    static NSString *annotationIdentifier = @"Photo";
    
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
    if (annotationView == nil)
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
    
    annotationView.canShowCallout = YES;
    
    UIButton *disclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    annotationView.rightCalloutAccessoryView = disclosureButton;
    
    return annotationView;
}

- (void)mapView:(MKMapView *)aMapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
    YCPhotoAnnotation *annotation = (YCPhotoAnnotation *)view.annotation;
    
    YCPhotoViewerViewController *viewController = [[YCPhotoViewerViewController alloc] init];
    viewController.edgesForExtendedLayout = UIRectEdgeNone;
    viewController.photoes = annotation.containedAnnotations;
    
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
    if ([view.annotation isKindOfClass:[YCPhotoAnnotation class]]) {
        YCPhotoAnnotation *annotation = (YCPhotoAnnotation *)view.annotation;
        [annotation updateSubtitleIfNeeded];
    }
}

@end
